#ifndef RABIN_H
#define RABIN_H

#include <sstream>

#include "signature_manager.h"
#include "GMPInt.h"



struct Rabin_privatekey {
    GMPInt p; // 私有密钥
    GMPInt q; // 私有密钥

    Rabin_privatekey() = default;
    Rabin_privatekey(const mpz_t p, const mpz_t q) : p(p), q(q) {}

    void set_by_str(const std::string& str){
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        mpz_set_str(p, item.c_str(), 10);

        std::getline(ss, item, ','); 
        mpz_set_str(q, item.c_str(), 10);
    }

    std::string to_str() const {
        char* str1 = mpz_get_str(nullptr, 10, p);
        std::string result(str1);
        free(str1);
        char* str2 = mpz_get_str(nullptr, 10, q);
        result += "," + std::string(str2);
        free(str2);
        return result;
    }
};


struct Rabin_publickey {
    GMPInt n; // 公钥

    Rabin_publickey() = default;
    Rabin_publickey(const mpz_t n) : n(n) {}

    void set_by_str(const std::string& str){
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        mpz_set_str(n, item.c_str(), 10);
    }

    std::string to_str() const {
        char* str1 = mpz_get_str(nullptr, 10, n);
        std::string result(str1);
        free(str1);
        return result;
    }
};

struct Rabin_publicparameter {
    bool is_valid = true;

    std::string to_str(){
        return "";
    }

    void set_by_str(const std::string& str){
        is_valid = true;
    }
};

struct Rabin_signature {
    GMPInt s;
    GMPInt u;

    Rabin_signature() = default;
    Rabin_signature(const mpz_t s, const mpz_t u) : s(s), u(u) {}

    
    std::string to_str() const {
        std::string result = s.to_str();
        result += "," + u.to_str();
        return result;
    }
    void set_by_str(const std::string& str) {
        std::istringstream ss{str};
        std::string item;
        std::getline(ss, item, ',');
        s.set_by_str(item);

        std::getline(ss, item, ','); 
        u.set_by_str(item);
    }
};

template<int key_length>
class Rabin : public SignatureAlgorithm<Rabin_privatekey, Rabin_publickey, Rabin_publicparameter, Rabin_signature> {
public:
    void generatepublicparameters(Rabin_publicparameter& publicParameters) override;
    void generateKeyPair(Rabin_privatekey& privatekey, Rabin_publickey& publickey, Rabin_publicparameter& publicparameter) override;
    Rabin_signature sign(const PlainMessage& message, const Rabin_privatekey& privatekey, const Rabin_publicparameter& publicparameter) override;
    bool verify(const PlainMessage& message, const Rabin_publickey& publickey, const Rabin_publicparameter& publicparameter, const Rabin_signature& signature) override;
};

template<int key_length>
struct Rabin_type_traits {
    using algo = Rabin<key_length>;
    using private_key = Rabin_privatekey;
    using public_key = Rabin_publickey;
    using params = Rabin_publicparameter;
    using signature = Rabin_signature;
};

extern template class Rabin<1024>;
extern template class Rabin<2048>;
extern template class Rabin<3072>;


#endif // RABIN_H